﻿using System;
using System.Collections.Generic;
using System.Text;
using FreeImageAPI;
using System.IO;
using System.Drawing;
using System.Diagnostics;

namespace jtifedit2 {
    public class PICS : IDisposable {
        String fpIn;

        public PICS(String fpIn) {
            this.fpIn = null;

            FIMULTIBITMAP tif = FreeImage.OpenMultiBitmap(FREE_IMAGE_FORMAT.FIF_TIFF, fpIn, false, true, false, FREE_IMAGE_LOAD_FLAGS.DEFAULT);
            try {
                int cx = FreeImage.GetPageCount(tif);
                for (int x = 0; x < cx; x++) {
                    FIBITMAP fib = FreeImage.LockPage(tif, x);
                    try {
                        alpic.Add(new PIC1(this, fib));
                    }
                    finally {
                        FreeImage.UnlockPage(tif, fib, false);
                    }
                }

                this.fpIn = fpIn;
            }
            finally {
                FreeImage.CloseMultiBitmap(tif, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
            }

        }

        public int FrameCount {
            get {
                return alpic.Count;
            }
        }

        protected internal List<PIC1> alpic = new List<PIC1>();

        public PIC1[] Pics {
            get {
                return alpic.ToArray();
            }
        }

        public PIC1 AddPage(FIBITMAP dib) {
            PIC1 p1 = new PIC1(this, FreeImage.Clone(dib));
            alpic.Add(p1);
            return p1;
        }

        public void MoveTo(int pifrm, int pito) {
            PIC1 o = alpic[pifrm];
            alpic.RemoveAt(pifrm);
            alpic.Insert(pito, o);
        }

        public PIC1 GetPage(int x) {
            return alpic[x];
        }

        public void Dispose() {

        }

        public void Save() {
            SaveTo(fpIn);
        }

        public void SaveTo(String fpInto) {
            FIMULTIBITMAP tif = FreeImage.OpenMultiBitmap(FREE_IMAGE_FORMAT.FIF_TIFF, fpInto, true, false, true, FREE_IMAGE_LOAD_FLAGS.DEFAULT);
            try {
                for (int x = 0; x < alpic.Count; x++) {
                    FIBITMAP dib = alpic[x].Pic;

                    FREE_IMAGE_COLOR_TYPE fict = FreeImage.GetColorType(dib);
                    if (fict == FREE_IMAGE_COLOR_TYPE.FIC_MINISBLACK) {
                        FreeImage.Invert(dib);
                        try {
                            Palette P = FreeImage.GetPaletteEx(dib);
                            RGBQUAD t0 = P.GetValue(0);
                            RGBQUAD t1 = P.GetValue(1);
                            P.SetValue(t0, 1);
                            P.SetValue(t1, 0);
                        }
                        catch (NullReferenceException) {

                        }
                    }

                    FreeImage.AppendPage(tif, dib);
                }
            }
            finally {
                FreeImage.CloseMultiBitmap(tif, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
            }
        }

        public void DeletePage(int i) {
            alpic.RemoveAt(i);
        }
    }

    public class PIC1 {
        PICS parent;
        FIBITMAP pic;

        protected internal PIC1(PICS parent, FIBITMAP pic) {
            this.parent = parent;
            this.pic = FreeImage.Clone(pic);
        }

        public int Index {
            get {
                int i = parent.alpic.IndexOf(this);
                Trace.Assert(i >= 0);
                return i;
            }
        }

        Size sizeThumb = new Size(200, 200);

        Bitmap CreateThumb(Bitmap pic) {
            Rectangle rcth = Fitrect.Fit(new Rectangle(Point.Empty, sizeThumb), pic.Size);
            Bitmap picth = new Bitmap(sizeThumb.Width, sizeThumb.Height);
            using (Graphics cv = Graphics.FromImage(picth)) {
                cv.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                cv.DrawImage(pic, rcth);
            }
            return picth;
        }

        public Bitmap CreateThumb2(Size size) {
            using (Bitmap dib = FreeImage.GetBitmap(pic)) {
                return CreateThumb(dib);
            }
        }

        public Bitmap CreateThumb(Size size) {
            FIBITMAP thumb = FreeImage.MakeThumbnail(pic, Math.Min(200, Math.Min(size.Width, size.Height)), true);
            try {
                return FreeImage.GetBitmap(thumb);
            }
            finally {
                FreeImage.UnloadEx(ref thumb);
            }
        }

        public Size Size {
            get {
                return new Size(
                    Convert.ToInt32(FreeImage.GetWidth(pic)),
                    Convert.ToInt32(FreeImage.GetHeight(pic))
                    );
            }
        }

        public FIBITMAP Pic { get { return pic; } }

        public void Rotate(int a) {
            FIBITMAP dib = FreeImage.RotateClassic(pic, a);
            uint rx = FreeImage.GetResolutionX(pic);
            uint ry = FreeImage.GetResolutionY(pic);
            FreeImage.SetResolutionX(dib, ((a % 180) == 0) ? rx : ry);
            FreeImage.SetResolutionY(dib, ((a % 180) == 0) ? ry : rx);
            Attach(dib);
        }

        public void RotateR90() { Rotate(270); }
        public void RotateL90() { Rotate(90); }

        public void SavePng(string fp) {
            FreeImage.Save(FREE_IMAGE_FORMAT.FIF_PNG, pic, fp, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
        }

        public void Replace(FIBITMAP newpic) {
            Attach(newpic);
        }

        public void Attach(FIBITMAP dib) {
            FreeImage.UnloadEx(ref pic);
            pic = FreeImage.Clone(dib);
        }

        public void SaveTIF(string fp) {
            FreeImage.Save(FREE_IMAGE_FORMAT.FIF_TIFF, pic, fp, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
        }
    }
}
